package com.bridge.aspect;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bridge.annotion.DictEscapeValue;
import com.bridge.annotion.DictResponse;
import com.bridge.utils.PageUtil;
import com.bridge.utils.ResUtils;
import com.bridge.vo.DictResponseData;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author bridge
 * @Date 2022/07/10/22:17
 */
@Slf4j
@Aspect
@Component
public class DictResponseAspect {

    /**
     * 转义后缀
     */
    private static final String SUFFIX = "dictTag";

    /**
     * 包名
     */
    private static final String REGEX_PACKAGE = "com.bridge.*.*";

    /**
     * 第一层
     */
    private static final String LEVEL_ONE = "one";

    /**
     * 第二层
     */
    private static final String LEVEL_TWO = "two";

    /**
     * list集合
     */
    private static final String LIST = "java.util.List";

    /**
     * set集合
     */
    private static final String SET = "java.util.Set";

    /**
     * 处理返回结果
     *
     * @param joinpoint    切点
     * @param dictResponse 注解
     * @param result       结果
     * @return
     */
    @AfterReturning(value = "@annotation(dictResponse)", returning = "result")
    public Object after(JoinPoint joinpoint, DictResponse dictResponse, Object result) {
        String method = joinpoint.getSignature().toString();
        log.info("解析注入JSON数据,method:{} start============>", method);
        long start = System.currentTimeMillis();
        processResult(result);
        long end = System.currentTimeMillis();
        log.info("解析注入JSON数据 ,method:{} 耗时:{} ms end============>", method, (end - start));
        return result;
    }


    /**
     * 处理结果
     *
     * @param result result
     */
    private void processResult(Object result) {
        Object data = ((ResUtils<?>) result).getData();
        if (data == null) {
            return;
        }

        if (data instanceof Collection) {
            List<JSONObject> rst = processData(data);
            ((ResUtils<List<JSONObject>>) result).setData(rst);
        } else if (data instanceof PageUtil) {
            PageUtil pageUtil = (PageUtil) data;
            pageUtil.setList(processData(((PageUtil<?>) data).getList()));
            ((ResUtils<PageUtil>) result).setData(pageUtil);
        } else {
            List<Object> list = new ArrayList<>();
            list.add(data);
            List<JSONObject> rst = processData(data);
            ((ResUtils<JSONObject>) result).setData(rst.get(0));
        }
    }

    /**
     * 处理返回数据
     *
     * @param data data
     * @return
     */
    private List<JSONObject> processData(Object data) {
        Set<String> sets = new HashSet<>();
        List<DictResponseData> dictResponseDataList = new ArrayList<>();
        // 获取存在注解的属性
        this.fillDicTypeList(data, sets, dictResponseDataList);

        // 不存在转义字段不处理
        List<JSONObject> itemList = new ArrayList<>();
        for (Object recordData : (Collection<?>) data) {
            ObjectMapper mapper = new ObjectMapper();
            itemList.add(getDictJsonObject(recordData, mapper));
        }
        if (CollectionUtils.isEmpty(dictResponseDataList)) {
            return itemList;
        }

        //获取数据字典
        Map<String, Map<String, String>> dicEnumMap = getDicEnumMap();

        Map<String, List<DictResponseData>> dictRstMap = dictResponseDataList.stream().collect(Collectors.groupingBy(DictResponseData::getLevel));
        itemList.forEach(item -> {
//        itemList.parallelStream().forEach(item -> {
            log.info(Thread.currentThread().getName() + "-----start---");
            List<DictResponseData> dictRst1 = dictRstMap.get(LEVEL_ONE);
            if (!CollectionUtils.isEmpty(dictRst1)) {
                dictRst1.forEach(k -> {
                    if (k.isIfAnnotation()) {
                        String dicKey = k.getDicKey();
                        String key = item.get(k.getRstFiled()) + "";
                        String textValue = translateDicKeyValue(dicEnumMap, dicKey, key);
                        item.put(k.getRstFiled() + SUFFIX, textValue);
                    }
                });
            }
            formatSubProcessResult(dicEnumMap, dictRstMap, item);
            log.info(Thread.currentThread().getName() + "-----end---");
        });
        return itemList;
    }

    /**
     * 获取数据字典的值 （公司项目查询数据库）
     *
     * @return
     */
    private Map<String, Map<String, String>> getDicEnumMap() {
        Map<String, Map<String, String>> dicEnumMap = new HashMap<>();
        Map<String, String> map1 = new HashMap<>();
        map1.put("admin", "admin的dict");
        map1.put("zhangshan", "zhangshan的dict");
        Map<String, String> map2 = new HashMap<>();
        map2.put("管理员", "管理员Dict");
        map2.put("张三", "张三Dict");
        dicEnumMap.put("user_name", map1);
        dicEnumMap.put("nick_name", map2);
        return dicEnumMap;
    }

    private JSONObject getDictJsonObject(Object recordData, ObjectMapper mapper) {
        String json = "{}";
        try {
            // 解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
            json = mapper.writeValueAsString(recordData);
        } catch (JsonProcessingException e) {
            log.error("Json解析失败：" + e);
        }
        JSONObject item = JSONObject.parseObject(json);
        return item;
    }


    /**
     * @param dicEnumMap 数据字典map
     * @param dictRstMap 字典结果Map
     * @param item       json
     */
    private void formatSubProcessResult(Map<String, Map<String, String>> dicEnumMap, Map<String, List<DictResponseData>> dictRstMap, JSONObject item) {
        List<DictResponseData> dict2 = dictRstMap.get(LEVEL_TWO);
        if (CollectionUtils.isEmpty(dict2)) {
            return;
        }
        for (DictResponseData rst : dict2) {
            if (rst.getRstType().matches(REGEX_PACKAGE) && !rst.getRstType().matches("com.bridge.enums.*")) {
                JSONObject jsonObject = (JSONObject) item.get(rst.getRstFiled());
                formatJsonObject(dicEnumMap, rst, jsonObject);
                item.put(rst.getRstFiled(), jsonObject);
            } else if (LIST.equals(rst.getRstType()) || SET.equals(rst.getRstType())) {
                JSONArray jsonArray = (JSONArray) item.get(rst.getRstFiled());
                if (jsonArray == null) {
                    continue;
                }
                for (Object obt : jsonArray) {
                    JSONObject jsonObject = (JSONObject) obt;
                    formatJsonObject(dicEnumMap, rst, jsonObject);
                }
                item.put(rst.getRstFiled(), jsonArray);
            }

        }

    }


    /**
     * json格式化
     *
     * @param dicEnumMap dicEnumMap
     * @param data       data
     * @param jsonObject jsonObject
     */
    private void formatJsonObject(Map<String, Map<String, String>> dicEnumMap, DictResponseData data,
                                  JSONObject jsonObject) {

        if (data == null || jsonObject == null || CollectionUtils.isEmpty(data.getSubList())) {
            return;
        }
        for (DictResponseData dictResponseData : data.getSubList()) {
            if (dictResponseData.isIfAnnotation()) {
                String value = jsonObject.getString(dictResponseData.getRstFiled());
                String textValue = this.translateDicKeyValue(dicEnumMap, dictResponseData.getDicKey(), value);
                jsonObject.put(dictResponseData.getRstFiled() + SUFFIX, textValue);
            }

        }

    }


    /**
     *   填充存在注解的属性
     * @param data data
     * @param sets sets
     * @param dictResponseDataList dictResponseDataList
     */
    private void fillDicTypeList(Object data, Set<String> sets, List<DictResponseData> dictResponseDataList) {
        for (Object list : (Collection<?>) data) {
            Field[] allFields = list.getClass().getDeclaredFields();
            if(CollectionUtils.isEmpty(dictResponseDataList)){
                fillDictResponseData(sets, dictResponseDataList, list, allFields);
            }
            for (Field field : allFields) {
                // 存在一级属性无需在添加
                try {
                    boolean flag = fillSubField(sets, dictResponseDataList.get(0), list, field);
                    if (flag) {
                        break;
                    }

                } catch (IllegalAccessException e) {
                    log.error("属性：{}，msg{},error-->{}", field.getName(), e.getMessage(), e);
                }
            }
        }

    }


    /**
     * 填充结果值
     * @param sets sets
     * @param dictResponseDataList dictResponseDataList
     * @param list list
     * @param allFields allFields
     */
    private void fillDictResponseData(Set<String> sets, List<DictResponseData> dictResponseDataList, Object list, Field[] allFields) {
        for (Field field : allFields) {
            DictResponseData data1 = new DictResponseData();
            data1.setLevel(LEVEL_ONE);
            fillDictResponseData(field, data1, sets);
            try {
                fillSubField(sets, data1, list, field);
            } catch (IllegalAccessException e) {
                log.error("属性：{}，msg{},error-->{}", field.getName(), e.getMessage(), e);
            }
            // 注解列 对象-》set>list
            if (LIST.equals(field.getType().getName()) || SET.equals(field.getType().getName())
                    || field.getType().getName().matches(REGEX_PACKAGE) || data1.isIfAnnotation()) {
                dictResponseDataList.add(data1);
            }

        }
    }

    private boolean fillSubField(Set<String> sets, DictResponseData data1, Object list, Field field) throws IllegalAccessException {

        if (!CollectionUtils.isEmpty(data1.getSubList())) {
            Map<String, List<DictResponseData>> towSubMap = data1.getSubList().stream().collect(Collectors.groupingBy(DictResponseData::getRstFiled));
            for (Map.Entry<String, List<DictResponseData>> entry : towSubMap.entrySet()) {
                List<DictResponseData> dataList = entry.getValue();
                if (dataList != null && dataList.size() > 1) {
                    return true;
                }
            }
        }
        //变量第二层属性
        if (field.getType().getName().matches(REGEX_PACKAGE)) {
            data1.setLevel(LEVEL_TWO);
            field.setAccessible(true);
            List<DictResponseData> dictVoList = new ArrayList<>();
            Object subObj = field.get(list);
            if (subObj == null) {
                return false;
            }
            Field[] allFields2 = list.getClass().getDeclaredFields();
            fillSubFields(sets, dictVoList, allFields2);
            data1.setSubList(dictVoList);
        } else if (LIST.equals(field.getType().getName()) || SET.equals(field.getType().getName())) {
            data1.setLevel(LEVEL_TWO);
            List<DictResponseData> dataList = new ArrayList<>();
            field.setAccessible(true);
            Object subObj = field.get(list);
            if (subObj == null) {
                return false;
            }
            for (Object subList : (Collection<?>) subObj) {
                Field[] allField2 = subList.getClass().getDeclaredFields();
                this.fillSubFields(sets, dataList, allField2);
            }
            data1.setSubList(dataList);
        }
        return false;
    }

    private void fillSubFields(Set<String> sets, List<DictResponseData> dictVoList, Field[] allFields2) {
        for (Field field : allFields2) {
            DictResponseData data2 = new DictResponseData();
            data2.setLevel(LEVEL_TWO);
            fillDictResponseData(field, data2, sets);
            if (data2.isIfAnnotation()) {
                dictVoList.add(data2);
            }
        }
    }


    private void fillDictResponseData(Field field, DictResponseData data, Set<String> sets) {
        data.setRstType(field.getType().getName());
        data.setRstFiled(field.getName());
        data.setIfAnnotation(false);
        if (field.getAnnotation(DictEscapeValue.class) != null) {
            String dickey = field.getAnnotation(DictEscapeValue.class).type();
            sets.add(dickey);
            data.setIfAnnotation(true);
            data.setDicKey(dickey);
        }
    }


    private String translateDicKeyValue(Map<String, Map<String, String>> dicEnumMap, String type, String key) {
        if (!StringUtils.hasText(type) || !StringUtils.hasText(key)
                || CollectionUtils.isEmpty(dicEnumMap)) {
            return "";
        }

        Map<String, String> dicMap = dicEnumMap.get(type);
        if (CollectionUtils.isEmpty(dicMap)) {
            return "";
        }
        return dicMap.get(key);
    }


}
